=begin pod :kind("Type") :subkind("class") :category("basic")

=TITLE class Parameter

=SUBTITLE Element of a Signature

    class Parameter { }

Represents a parameter, for purpose of introspection.

The usual way to obtain a C<Parameter> object is to create a signature,
and call C<.params> on it to obtain a list of the parameters.

    my $sig   = :(Str $x);
    my $param = $sig.params[0];
    say $param.type;              # OUTPUT: «Str()␤»

See L<Signature|/type/Signature> for more information, and also for an explanation
on what most of the concepts related to parameters mean.

=head1 Methods

=head2 method name

Defined as:

    method name(Parameter:D: --> Str:D)

Returns the parameter name, which includes
all L<sigils|/language/variables#Sigils> and
L<twigils|/language/variables#Twigils>.
This name is used internally when applied to code, or in a declaration
to determine the declared the name.  This name is not necessarily
usable by a caller – if it is, it will also appear as an
L<alias|#method named_names>.  Often, the name will be chosen descriptively
as a form of self-documentation.

If the parameter is anonymous, an empty string will be returned.

B<Note:> Before Rakudo version 2020.08 the return value for an anonymous
parameter was C<Nil>.

=for code
my Signature $sig = :(Str $x, Bool);
say $sig.params[0].name;                 # OUTPUT: «$x␤»
say $sig.params[1].name;                 # OUTPUT: «␤»

=head2 method usage-name

Defined as:

    method usage-name(Parameter:D: --> Str:D)

Returns the parameter name without any
L<sigils|/language/variables#Sigils> and
L<twigils|/language/variables#Twigils>.

If the parameter is anonymous, an empty string will be returned.

B<Note:> Before Rakudo version 2020.08 the return value for an anonymous
parameter was C<Nil>.

=for code
my Signature $sig = :(Str $x, Str @*l, Bool);
say $sig.params[0].usage-name;           # OUTPUT: «x␤»
say $sig.params[1].usage-name;           # OUTPUT: «l␤»
say $sig.params[2].usage-name;           # OUTPUT: «␤»

=head2 method sigil

Defined as:

    method sigil(Parameter:D: --> Str:D)

Returns a string containing the parameter's sigil, for a looser
definition of "sigil" than what is considered part of
the parameter's L«C<name>|#method name».  Still returns a sigil even
if the parameter is anonymous.

This "sigil" is actually an introspection used to help determine
the normal binding style of a parameter, if it has not been altered
through a L<trait|/type/Signature#Parameter_traits_and_modifiers>.

=begin table
Sigil | Will bind to           | Default behavior
===================================================
 $    | Scalar                 | Generate new Scalar, use instead of Scalar in argument, if any
 @    | Positional             | Bind directly to the argument
 @    | PositionalBindFailover | If binding failed, call argument's .cache method, bind to result
 %    | Associative            | Bind directly to the argument
 &    | Callable               | Bind directly to the argument
 \    | (anything)             | Bind directly to the argument, keep existing Scalar, if any
=end table

Also, C<|> will bind to all remaining arguments and make new C<Capture> if needed.

=head2 method type

Returns the L<nominal type constraint|/type/Signature#Type_constraints> of
the parameter.

=head2 method coerce_type

Returns the L<coercion type|/syntax/Coercion%20type> of the parameter.

=head2 method constraints

Returns L<additional constraints|/type/Signature#Type_constraints> on the
parameter (usually as an C<all>-Junction).

=head2 method named

Defined as:

    method named(Parameter:D: --> Bool:D)

Returns C<True> if it's a L<named parameter|/type/Signature#Positional_vs._named_arguments>.

    my Signature $sig = :(Str $x, Bool :$is-named);
    say $sig.params[0].named;                          # OUTPUT: «False␤»
    say $sig.params[1].named;                          # OUTPUT: «True␤»

=head2 method named_names

Defined as:

    method named_names(Parameter:D: --> List:D)

Returns the list of externally usable names/aliases for a
L<named parameter|/type/Signature#Positional_vs._named_arguments>.

=head2 method positional

Defined as:

    method positional(Parameter:D: --> Bool:D)

Returns C<True> if the parameter is
L<positional|/type/Signature#Positional_vs._named_arguments>.

    my Signature $sig = :(Str $x, Bool :$is-named);
    say $sig.params[0].positional;                     # OUTPUT: «True␤»
    say $sig.params[1].positional;                     # OUTPUT: «False␤»

=head2 method slurpy

Defined as:

    method slurpy(Parameter:D: --> Bool:D)

Returns C<True> for
L<slurpy parameters|/type/Signature#Slurpy_parameters>.

=head2 method twigil

Defined as:

    method twigil(Parameter:D: --> Str:D)

Returns a string containing the twigil part of the parameter's name.

=head2 method optional

Defined as:

    method optional(Parameter:D: --> Bool:D)

Returns C<True> for
L<optional parameters|/type/Signature#Optional_and_mandatory_arguments>.

=head2 method raw

Defined as:

    method raw(Parameter:D: --> Bool:D)

Returns C<True> for raw parameters.

    sub f($a, $b is raw, \c) {
        my $sig = &?ROUTINE.signature;
        for ^$sig.params.elems {
            say $sig.params[$_].raw;
        }
    }
    f(17, "4711", 42); # OUTPUT: «False␤True␤True␤»

Raw parameters bind either a variable or a value passed to it, with
no decontainerization taking place.  That means that if a variable was passed
to it, you can assign to the parameter. This is different from
L<rw|#method_rw>-parameter which can only bind to variables, never to values.

This is the normal behavior for parameters declared with a
L<sigil|#method sigil> of 'C<\>', which is not really a sigil insofar
as it is only used on the parameter.

    sub f(\x) {
        x = 5;
    }
    f(my $x);   # works
    f(42);      # dies
    CATCH { default { put .^name, ': ', .Str } };
    # OUTPUT: «X::Assignment::RO: Cannot modify an immutable Int␤»

Other parameters may become raw through use of the 'C<is raw>'
L<trait|/type/Signature#Parameter_traits_and_modifiers>.  These still use
their sigil in code.

    sub f($x is raw) {
        $x = 5;
    }

When used with slurpy list parameters, the C<is raw> trait will cause the list
of arguments given to be packed into a C<List> instead of an C<Array>, which
prevents them from being containerized with C<Scalar>. This is the default
behavior when using C<+> with a sigilless parameter:

    my @types is List = Mu, Any;
    say -> *@l { @l }(@types)[0] =:= @types[0];        # OUTPUT: «False␤»
    say -> +@l { @l }(@types)[0] =:= @types[0];        # OUTPUT: «False␤»
    say -> +l { l }(@types)[0] =:= @types[0];          # OUTPUT: «True␤»
    say -> *@l is raw { @l }(@types)[0] =:= @types[0]; # OUTPUT: «True␤»

=head2 method capture

Defined as:

    method capture(Parameter:D: --> Bool:D)

Returns C<True> for parameters that capture the rest of the argument list into
a single L<Capture|/type/Capture> object.

    sub how_many_extra_positionals($!, |capture) { capture.elems.say }
    how_many_extra_positionals(0, 1, 2, 3);                        # OUTPUT: «3»
    say &how_many_extra_positionals.signature.params[1].capture;   # OUTPUT: «True␤»

Like raw parameters, C<Capture> parameters do not force any context on the
values bound to them, which is why their sigils are only used in
declarations.

=head2 method rw

Defined as:

    method rw(Parameter:D: --> Bool:D)

Returns C<True> for L<C<is rw>|/type/Signature#Parameter_traits_and_modifiers>
parameters.

    my Signature $sig = :(Str $x is rw, Bool :$is-named);
    say $sig.params[0].rw;                             # OUTPUT: «True␤»
    say $sig.params[1].rw;                             # OUTPUT: «False␤»

=head2 method copy

Defined as:

    method copy(Parameter:D: --> Bool:D)

Returns C<True> for L<C<is copy>|/type/Signature#Parameter_traits_and_modifiers>
parameters.

    my Signature $sig = :(Str $x, Bool :$is-named is copy);
    say $sig.params[0].copy;                           # OUTPUT: «False␤»
    say $sig.params[1].copy;                           # OUTPUT: «True␤»

=head2 method readonly

Defined as:

    method readonly(Parameter:D: --> Bool:D)

Returns C<True> for read-only parameters (the default).

    my Signature $sig = :(Str $x is rw, Bool :$is-named);
    say $sig.params[0].readonly;                       # OUTPUT: «False␤»
    say $sig.params[1].readonly;                       # OUTPUT: «True␤»

=head2 method invocant

Defined as:

    method invocant(Parameter:D: --> Bool:D)

Returns C<True> if the parameter is the
L<invocant parameter|/type/Signature#Parameter_separators>.

    my Signature $sig = :($i : Str $x is rw, Bool :$is-named);
    say $sig.params[0].invocant;                       # OUTPUT: «True␤»
    say $sig.params[1].invocant;                       # OUTPUT: «False␤»

=head2 method default

Defined as:

    method default(Parameter:D: --> Code:_)

Returns a closure that upon invocation returns the
L<default value|/type/Signature#Optional_and_mandatory_arguments> for
this parameter, or C<Code> if no default was provided.

B<Note:> Before Rakudo version 2020.08 the return value for a parameter
with no default value was C<Any>.

=for code
my $sig = :($a, $b = 12);
say $sig.params[0].default;        # OUTPUT: «(Code)␤»
say $sig.params[1].default.();     # OUTPUT: «12␤»

=head2 method type_captures

Defined as:

    method type_captures(Parameter:D: --> List:D)

Returns a list of variable names of L<type captures|/type/Signature#Type_captures> associated with this
parameter.  Type captures define a type name within the attached code,
which is an alias to the type gleaned from the argument during a call.

    sub a(::T ::U $x) { T.say }
    a(8);                                       # OUTPUT: «(Int)␤»
    say &a.signature.params[0].type_captures;   # OUTPUT: «(T U)␤»
    sub b($x) { $x.^name.say }
    a(8);                                       # OUTPUT: «Int␤»

The type used may change from call to call.  Once they are defined,
type captures can be used wherever you would use a type, even later
in the same signature:

=begin code
sub c(::T $x, T $y, $z) { my T $zz = $z };
c(4, 5, 6);          # OK

try c(4, 5, "six");
given $! { .message.say };
# OUTPUT: «Type check failed in assignment to $zz; expected Int but got Str ("six")␤»

try c("four", 5, "six");
given $! { .message.say };
# OUTPUT: «Type check failed in binding to parameter '$y'; expected Str but got Int (5)␤»
=end code

Type captures may be used at the same time as
L<type constraints|/type/Signature#Type_constraints>.

=begin code
sub d(::T Numeric $x, T $y) {};
d(4, 5);            # OK
d(4e0, 5e0);        # OK

try d(4e0, 5);
given $! { .message.say };
# OUTPUT: «Type check failed in binding to parameter '$y'; expected Num but got Int (5)␤»

try d("four", "five");
given $! { .message.say };
# OUTPUT: «Type check failed in binding to parameter '$x'; expected Numeric but got Str ("four")␤»
=end code

=head2 method sub_signature

Defined as:

    method sub_signature(Parameter:D: --> Signature:_)

If the parameter has a
L<sub-signature|/type/Signature#Sub-signatures>,
returns a C<Signature> object for it.  Otherwise returns C<Signature>.

B<Note:> Before Rakudo version 2020.08 the return value for a parameter
with no sub-signature was C<Any>.

=for code
my Signature $sig = :(@array ($first, *@rest), @other);
say $sig.params[0].sub_signature;     # OUTPUT:«($first, *@rest)␤»
say $sig.params[1].sub_signature;     # OUTPUT:«(Signature)␤»

=head2 method prefix

Defined as:

    method prefix(Parameter:D: --> Str:D)

If the parameter is L«slurpy|/type/Signature#Slurpy_parameters»,
returns the marker (e.g., C«*», C«**», or C«+») the parameter was declared
with. Otherwise, returns an empty string.

    my Signature $flat-slurpy = :($a, *@b);
    say $flat-slurpy.params[0].prefix; # OUTPUT:«␤»
    say $flat-slurpy.params[1].prefix; # OUTPUT:«*␤»

    my Signature $unflat-slurpy = :($a, **@b);
    say $unflat-slurpy.params[0].prefix; # OUTPUT:«␤»
    say $unflat-slurpy.params[1].prefix; # OUTPUT:«**␤»

    my Signature $sar-slurpy = :($a, +@b);
    say $sar-slurpy.params[0].prefix; # OUTPUT:«␤»
    say $sar-slurpy.params[1].prefix; # OUTPUT:«+␤»

=head2 method suffix

Defined as:

    method suffix(Parameter:D: --> Str:D)

Returns the C«?» or C«!» marker a parameter was declared with, if any. Otherwise,
returns the empty string.

    my Signature $pos-sig = :($a, $b?);
    say $pos-sig.params[0].suffix; # OUTPUT: «␤»
    say $pos-sig.params[1].suffix; # OUTPUT: «?␤»

    my Signature $named-sig = :(:$a!, :$b);
    say $named-sig.params[0].suffix; # OUTPUT: «!␤»
    say $named-sig.params[1].suffix; # OUTPUT: «␤»

=head1 Runtime creation of Parameter objects (6.d, 2019.03 and later)

   Parameter.new( ... )

In some situations, specifically when working with the
L<MetaObject Protocol|/language/mop>, it makes sense to create C<Parameter>
objects programmatically.  For this purpose, you can call the C<new> method
with the following named parameters:

=item name

Optional.  The name of the parameter, if any.  Can be specified in the same
way as in a C<Signature>.  So it may contain specific additional information,
such as a sigil (C<$>, C<@>, C<%> or C<&>), a C<:> prefix to indicate a named
parameter, a twigil (C<.> or C<!>) to indicate public / private attribute
binding, a postfix C<!> or C<?> to indicate an optional / mandatory parameter,
and the various combinations of C<+>, C<*>, C<**> prefixes to indicate
slurpiness types and C<|> to indicate a C<Capture>.

=item type

Optional.  The type of the parameter.  Assumes C<Any> if not specified.

=item default

Optional.  The value of the parameter if the parameter is optional and no
argument has been given for that parameter.  Assumes not initialization if
no argument has been given, which would fall back to the (implicit) type
of the parameter.

=item where

Optional.  Additional constraints to be applied to any argument to match with
this parameter.  Does not set any additional constraints by default.

=item is-copy

Optional.  Allows one to set the "is copy" flag on the parameter.  Does not
set the flag by default.

=item is-raw

Optional.  Allows one to set the "is raw" flag on the parameter.  Does not
set the flag by default.

=item is-rw

Optional.  Allows one to set the "is rw" flag on the parameter.  Does not
set the flag by default.

=item named

Optional.  Indicates whether the parameter is a named parameter or not.
Should only be specified if the C<:> prefix is B<not> specified in the name
and a named parameter is required.

=item optional

Optional.  Indicates whether the parameter is optional or not.  Should only be
specified if the C<?> postfix is B<not> specified in the name and an optional
parameter is required.

=item mandatory

Optional.  Indicates whether the parameter is mandatory or not.  Should only be
specified if the C<!> postfix is B<not> specified in the name and a mandatory
parameter is required.

=item multi-invocant

Optional.  Indicates whether the parameter should be considered in
multi-dispatch or not.  Defaults to C<True>, so one would need to do
C<:!multi-invocant> to make the parameter B<not> be considered in
multi-dispatch.

=item sub-signature

Optional.  Specifies any C<Signature> that should be applied to the
parameter to deconstruct it.  By default, no signature is to be applied.

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
